﻿using Microsoft.Windows.Shell;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Runtime.InteropServices;
using System.Security;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Interop;
using System.Windows.Media;
using UBCon.Controls;
using UBCon.Core;
using UBCon.Core.Commands;

namespace UBCon.Controls
{
    /// <summary>
    /// Represent message box root visual.
    /// </summary>
    [TemplatePart(Name = PART_IconName, Type = typeof(Image))]
    public class MessageBoxControl : Window
    {
 
        #region Constructors

        /// <summary>
        /// Default static constructor.
        /// </summary>
        static MessageBoxControl()
        {
            Type ownerType = typeof(MessageBoxControl);
            MessageBoxControl.DefaultStyleKeyProperty.OverrideMetadata(ownerType,
                 new FrameworkPropertyMetadata(ownerType)
                 );

            WindowStyleProperty.OverrideMetadata(ownerType,
                new FrameworkPropertyMetadata(
                    WindowStyle.None, new PropertyChangedCallback(OnWindowStyleChanged), new CoerceValueCallback(CoerceWindowStyle)));

            ResizeModeProperty.OverrideMetadata(ownerType, new FrameworkPropertyMetadata(ResizeMode.NoResize));


        }

        /// <summary>
        /// Default constructor.
        /// </summary>
        public MessageBoxControl()
            : base()
        {
            SetHook();

            //Here we register all commands.
            RegisterCommands();

            Loaded += OnMessageBoxWindowLoaded;

        }

        #endregion

        #region Properties

        /// <summary>
        /// Type: System.Windos.MessageBoxResult.
        /// Specifies which message box button that a user clicks. 
        /// System.Windos.MessageBoxResult is returned by this window.
        /// </summary>
        internal MessageBoxResult MBDialogResult 
        {
            get 
            {
                return _dialogResult;
            }
            set 
            {
                _dialogResult = value;
            }
        }

        /// <summary>
        /// A value that specifies the default result of the message box.
        /// </summary>
        internal MessageBoxResult DefaultResult 
        {
            get 
            {
                return defaultResult;
            }
            set 
            {
                defaultResult = value;
            }
        }
        /// <summary>
        /// Gets or sets a boolean value indicating whether close button is visible or not.
        /// This is a dependency property.
        /// </summary>
        [Bindable(true),
        Browsable(true),
        ReadOnly(false),
        Category("Appearance")]
        public bool IsCloseButtonEnabled
        {
            get { return (bool)GetValue(IsCloseButtonEnabledProperty); }
            set { SetValue(IsCloseButtonEnabledProperty, value); }
        }

        // Using a DependencyProperty as the backing store for IsCloseButtonEnabled.  This enables animation, styling, binding, etc...
        public static readonly DependencyProperty IsCloseButtonEnabledProperty =
            DependencyProperty.Register("IsCloseButtonEnabled", typeof(bool), typeof(MessageBoxControl), 
            new PropertyMetadata(true));
        
        /// <summary>
        /// Gets or sets default style of the button.
        /// This is a dependency property.
        /// </summary>
        public Style DefaultButtonStyle
        {
            get { return (Style)GetValue(DefaultButtonStyleProperty); }
            set { SetValue(DefaultButtonStyleProperty, value); }
        }

        /// <summary>
        /// Identifies UBCon.Controls.MessageBoxControl.DefaultButtonStyle dependency property.
        /// </summary>
        public static readonly DependencyProperty DefaultButtonStyleProperty =
            DependencyProperty.Register("DefaultButtonStyle", typeof(Style), typeof(MessageBoxControl), 
            new PropertyMetadata(null));

        
        /// <summary>
        /// Specifies the image which is displayed be a message box.
        /// </summary>
        public MessageBoxImage MessageBoxImage
        {
            get { return (MessageBoxImage)GetValue(MessageBoxImageProperty); }
            set { SetValue(MessageBoxImageProperty, value); }
        }

        /// <summary>
        /// Identifies UBCon.Controls.MessageBoxControl.MessageBoxImage dependency property.
        /// </summary>
        public static readonly DependencyProperty MessageBoxImageProperty =
            DependencyProperty.Register("MessageBoxImage", typeof(MessageBoxImage), typeof(MessageBoxControl), 
            new FrameworkPropertyMetadata(MessageBoxImage.Information));

        private MessageBoxButton _messsageBoxButton = MessageBoxButton.OK;

        /// <summary>
        /// Type: System.Windows.MessageBoxButton.
        /// Specifies the buttons which are displayed on a message box. Used as an argument of the Overload: UBCon.Controls.MessageBox.Show method.
        /// </summary>
        public MessageBoxButton MessageBoxButton
        {
            get
            {
                return _messsageBoxButton;
            }
            set
            {
                _messsageBoxButton = value;
                IsCloseButtonEnabled = !(_messsageBoxButton == System.Windows.MessageBoxButton.OK || _messsageBoxButton == System.Windows.MessageBoxButton.YesNo);
            }
        }
        #endregion

        #region Depenency Property Changed Callbacks

        /// <summary>
        /// Coerces WindowStyle property.
        /// </summary>
        /// <param name="sender">Type: System.Windows.DependencyObject. The object that the property exists on. When the callback is invoked, the property system will pass this value.</param>
        /// <param name="value">Type: System.Object. The new value of the property, prior to any coercion attempt.</param>
        /// <returns>Type: System.Object. The coerced value (with appropriate type). </returns>
        private static object CoerceWindowStyle(DependencyObject sender, Object value)
        {
            return WindowStyle.None;
        }

        /// <summary>
        /// Invoked when WindowStyle property changes.
        /// </summary>
        /// <param name="sender">Type: System.Windows.DependencyObject. The DependencyObject on which the property has changed value.</param>
        /// <param name="e">Type: System.Windows.DependencyPropertyChangedEventArgs. Event data that is issued by any event that tracks changes to the effective value of this property.</param>
        private static void OnWindowStyleChanged(DependencyObject sender, DependencyPropertyChangedEventArgs e)
        {

        }

        #endregion

        #region Overrieds

        /// <summary>
        /// When overridden in a derived class, measures the size in layout required 
        /// for child elements and determines a size for the FrameworkElement-derived class.
        /// </summary>
        /// <param name="availableSize">The available size that this element can 
        /// give to child elements. Infinity can be specified as a value to indicate 
        /// that the element will size to whatever content is available.</param>
        /// <returns>The size that this element determines it needs during layout, based on 
        /// its calculations of child element sizes.</returns>
        protected override Size MeasureOverride(Size availableSize)
        {
            VerifyAccess();
            if (VisualChildrenCount > 0)
            {
                UIElement child = GetVisualChild(0) as UIElement;
                if (child != null)
                {
                    child.Measure(availableSize);
                    measuredSize.Width = Math.Min(availableSize.Width, child.DesiredSize.Width);
                    measuredSize.Height = Math.Min(availableSize.Height, child.DesiredSize.Height);
                    return measuredSize;
                }
            }
            return base.MeasureOverride(availableSize);
        }

        /// <summary>
        /// When overridden in a derived class, is invoked whenever application 
        /// code or internal processes call ApplyTemplate.
        /// </summary>
        public override void OnApplyTemplate()
        {
            base.OnApplyTemplate();
            mainBorder = GetTemplateChild(partOuterBorder) as FrameworkElement;
            titleText = GetTemplateChild(partTitleText) as TextBlock;
            icon = GetTemplateChild(PART_IconName) as Image;

            if (icon != null)
            {
                icon.MouseLeftButtonDown += new MouseButtonEventHandler(IconMouseLeftButtonDown);
                icon.MouseRightButtonDown += new MouseButtonEventHandler(IconMouseRightButtonDown);
            }

            _itemsHost = GetTemplateChild(_itemsHostName) as Panel;

            if (_itemsHost == null)
            {
                throw new NullReferenceException("Parameter name: buttons panel. Refer to documentation for message box");
            }

            BuildButtons();
        }
      
        /// <summary>
        /// Invalidates the arrange state (layout) for the element. 
        /// After the invalidation, the element will have its layout updated, which will occur 
        /// asynchronously unless subsequently forced by UpdateLayout. (Inherited from UIElement.)
        /// </summary>
        /// <param name="finalSize">The finalSize size that this element can give to child elements. 
        /// Infinity can be specified as a value to indicate that the element will size to whatever content is available.</param>
        /// <returns>The size that this element determines it needs during layout, based on its calculations of child element sizes.</returns>
        protected override Size ArrangeOverride(Size arrangeBounds)
        {
            VerifyAccess();

            if (VisualChildrenCount > 0)
            {
                UIElement child = this.GetVisualChild(0) as UIElement;

                if (child != null)
                {
                    child.Arrange(new Rect(arrangeBounds));
                }
                return arrangeBounds;
            }
            return base.ArrangeOverride(arrangeBounds);
        }

        #endregion

        #region Private Methods

        /// <summary>
        /// Builds related buttons of the message box.
        /// </summary>
        private void BuildButtons()
        {
            Button btn = null;
            switch (this.MessageBoxButton)
            {
                case System.Windows.MessageBoxButton.OK:

                    btn = GetButton("Ok");
                    SetBinding(btn);
                    btn.Click += OnButtonPressed;
                    ok = btn;
                    _itemsHost.Children.Add(btn);

                    break;
                case System.Windows.MessageBoxButton.OKCancel:

                    btn = GetButton("Ok");
                    SetBinding(btn);
                    btn.Click += OnButtonPressed;
                    ok = btn;
                    _itemsHost.Children.Add(btn);

                    btn = GetButton("Cancel");
                    SetBinding(btn);
                    btn.Click += OnButtonPressed;
                    btn.IsCancel = true;
                    cancel = btn;
                    _itemsHost.Children.Add(btn);

                    break;
                case System.Windows.MessageBoxButton.YesNo:

                    btn = GetButton("Yes");
                    SetBinding(btn);
                    btn.Click += OnButtonPressed;
                    yes = btn;
                    _itemsHost.Children.Add(btn);

                    btn = GetButton("No");
                    SetBinding(btn);
                    btn.Click += OnButtonPressed;
                    no = btn;
                    _itemsHost.Children.Add(btn);

                    break;
                case System.Windows.MessageBoxButton.YesNoCancel:

                    btn = GetButton("Yes");
                    btn.Tag = "Yes";
                    SetBinding(btn);
                    btn.Click += OnButtonPressed;
                    yes = btn;
                    _itemsHost.Children.Add(btn);

                    btn = GetButton("No");
                    btn.Tag = "No";
                    SetBinding(btn);
                    btn.Click += OnButtonPressed;
                    no = btn;
                    _itemsHost.Children.Add(btn);

                    btn = GetButton("Cancel");
                    btn.Tag = "Cancel";
                    SetBinding(btn);
                    btn.Click += OnButtonPressed;
                    cancel = btn;
                    cancel.IsCancel = true;
                    _itemsHost.Children.Add(btn);

                    break;
            }

            SetDefaultResultButton();


        }

        /// <summary>
        /// Sets the button the which is focused when the window is loaded.
        /// </summary>
        private void SetDefaultResultButton() 
        {
            switch (this.MessageBoxButton) 
            {
                case System.Windows.MessageBoxButton.OK:

                    defaultFocusBtn = ok;
                    break;
                case System.Windows.MessageBoxButton.OKCancel:
                    if (DefaultResult == MessageBoxResult.OK) 
                    {
                        defaultFocusBtn = ok;
                    }
                    else if (DefaultResult == MessageBoxResult.Cancel) 
                    {
                        defaultFocusBtn = cancel;
                    }
                    break;
                case System.Windows.MessageBoxButton.YesNo:

                    if (DefaultResult == MessageBoxResult.Yes) 
                    {
                        defaultFocusBtn = yes;
                    }
                    else if (DefaultResult == MessageBoxResult.No) 
                    {
                        defaultFocusBtn = no;
                    }
                    break;
                case System.Windows.MessageBoxButton.YesNoCancel:

                    if (DefaultResult == MessageBoxResult.Yes) 
                    {
                        defaultFocusBtn = yes;
                    }
                    else if (DefaultResult == MessageBoxResult.No) 
                    {
                        defaultFocusBtn = no;
                    }
                    else if (DefaultResult == MessageBoxResult.Cancel) 
                    {
                        defaultFocusBtn = cancel;
                    }

                    break;
            }
            
        }

        private void SetBinding(Button btn)
        {
            BindingOperations.SetBinding
                           (
                               btn,
                               Button.StyleProperty,
                               new Binding(defaultButtonStyleName) { Source = this, Mode = BindingMode.OneWay }
                           );

        }

        /// <summary>
        /// Builds a new button with specified content.
        /// </summary>
        /// <param name="content">Content text.</param>
        /// <returns>Button</returns>
        private Button GetButton(string content)
        {
            Button btn = new Button()
            {
                Content = content,
                HorizontalContentAlignment = System.Windows.HorizontalAlignment.Center,
                VerticalContentAlignment = System.Windows.VerticalAlignment.Center,
                Height = 22,
                Margin = new Thickness(5, 0, 5, 0),
                Width = 65

            };
            
            return btn;
        }

        /// <summary>
        /// Sets low-level window procedure.
        /// </summary>
        private void SetHook()
        {
            EventHandler handler = null;

            handler = delegate(object sender, EventArgs e)
            {
                base.SourceInitialized -= handler;

                handler = null;

                HwndSource source = (HwndSource)PresentationSource.FromVisual(this);
                _hwnd = source.Handle;
                NativeMethods.RECT _clientRect, _windowRect;
                NativeMethods.GetWindowRect(_hwnd, out _windowRect);
                NativeMethods.GetClientRect(_hwnd, out _clientRect);
                _resizeFrameBorderSize = (_windowRect.Width - _clientRect.Width) / 2;
               
                this.HideButtons();


                source.AddHook(new HwndSourceHook(WndProc));
            };
            base.SourceInitialized += handler;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="hwnd">Type: System.IntPtr. Window handler.</param>
        /// <param name="lParam"></param>
        /// <param name="handled"></param>
        /// <param name="result"></param>
        [SecurityCritical, SecuritySafeCritical]
        private void WndProcHitTest(System.IntPtr hwnd, System.IntPtr lParam, ref bool handled, ref System.IntPtr result)
        {
            int xy = lParam.ToInt32();
            System.Windows.Point point = new System.Windows.Point(NativeMethods.SignedLoWord(xy), NativeMethods.SignedHiWord(xy));
            NativeMethods.RECT rect = new NativeMethods.RECT();
            NativeMethods.GetWindowRect(hwnd, out rect);
            System.Windows.Rect wndRect = new System.Windows.Rect(rect.Left, rect.Top, rect.Right - rect.Left, rect.Bottom - rect.Top);
            NativeMethods.HT ht = this.NCHITTEST(point, wndRect);
            result = new System.IntPtr((int)ht);
            handled = ht != NativeMethods.HT.NOWHERE;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="point"></param>
        /// <param name="wndRect"></param>
        /// <returns></returns>
        [SecurityCritical, 
        SecuritySafeCritical]
        private NativeMethods.HT NCHITTEST(System.Windows.Point point, System.Windows.Rect wndRect)
        {
            const double borderSize = 6.0;
            const double titleHeight = 34.0;

            if (point.Y < wndRect.Top + borderSize)
            {
                if (point.X < wndRect.Left + borderSize) return NativeMethods.HT.TOPLEFT;
                if (point.X > wndRect.Right - borderSize) return NativeMethods.HT.TOPRIGHT;
                return NativeMethods.HT.TOP;
            }
            if (point.Y > wndRect.Bottom - borderSize)
            {
                if (point.X < wndRect.Left + borderSize) return NativeMethods.HT.BOTTOMLEFT;
                if (point.X > wndRect.Right - borderSize) return NativeMethods.HT.BOTTOMRIGHT;
                return NativeMethods.HT.BOTTOM;
            }
            if (point.X < wndRect.Left + borderSize)
            {
                return NativeMethods.HT.LEFT;
            }
            if (point.X > wndRect.Right - borderSize) return NativeMethods.HT.RIGHT;
            if (point.Y < wndRect.Top + titleHeight)
            {
                Point localPoint = ScreenToLocal(point);
                IInputElement e = InputHitTest(localPoint);

                if (e == null)
                {
                    return NativeMethods.HT.CAPTION;
                }
                else
                {
                    if (e == mainBorder)
                    {

                        return NativeMethods.HT.CAPTION;
                    }

                    UIElement ue = e as UIElement;

                    if (ue == null ||
                            !ue.IsHitTestVisible ||
                                ue == titleText)
                    {
                        return NativeMethods.HT.CAPTION;
                    }
                }
            }
            return NativeMethods.HT.NOWHERE;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="point"></param>
        /// <returns></returns>
        [SecurityCritical, 
        SecuritySafeCritical]
        private Point ScreenToLocal(System.Windows.Point point)
        {
            NativeMethods.RECT rect;
            NativeMethods.GetWindowRect(new WindowInteropHelper(this).Handle, out rect);
            Matrix matrix = PresentationSource.FromVisual(this).CompositionTarget.TransformFromDevice;
            point.Offset((double)(-1 * rect.Left), (double)(-1 * rect.Top));
            point.X *= matrix.M11;
            point.Y *= matrix.M22;
            return point;
        }

        /// <summary>
        /// Registers commands.
        /// </summary>
        private void RegisterCommands()
        {
            Type ownerType = typeof(MessageBoxControl);

            CommandBindings.Add(new CommandBinding(CloseCommand, new ExecutedRoutedEventHandler(PerformClose)));

            CommandManager.RegisterClassCommandBinding(ownerType, new CommandBinding(SystemCommands.ShowSystemMenuCommand, SystemMenuExecuted, SystemMenuCanExecute));
        }

        #endregion

        #region Event Handlers

        /// <summary>
        /// Generic handler for all buttons' click event.
        /// </summary>
        /// <param name="sender">Owner of the event.</param>
        /// <param name="e">Event data for the evet.</param>
        private void OnButtonPressed(object sender, RoutedEventArgs e) 
        {
            e.Handled = true;

            Button btn = sender as Button;
            
            if (btn == ok) 
            {
                MBDialogResult = MessageBoxResult.OK;
            }
            else if (btn == cancel) 
            {
                MBDialogResult = MessageBoxResult.Cancel;
            }
            else if (btn == yes) 
            {
                MBDialogResult = MessageBoxResult.Yes;
            }
            else if (btn == no) 
            {
                MBDialogResult = MessageBoxResult.No;
            }

            if (Keyboard.FocusedElement != null) 
            {
                Keyboard.Focus(null);
            }

            Close();
       
        }

      
        /// <summary>
        /// Invoked when Close command is executed.
        /// </summary>
        /// <param name="sender">Owner of command.</param>
        /// <param name="e">Event data for the event.</param>
        private void PerformClose(object sender, ExecutedRoutedEventArgs e)
        {
            if (MessageBoxButton == System.Windows.MessageBoxButton.OKCancel ||
                MessageBoxButton == System.Windows.MessageBoxButton.YesNoCancel)
            {
                MBDialogResult = MessageBoxResult.Cancel;
            }
            Close();
        }


        /// <summary>
        /// Invoked when the left mouse button is pressed while the pointer is over this control.
        /// </summary>
        /// <param name="sender">Owner of the event.</param>
        /// <param name="e">Event arguments for the routed event that is raised by UIElement.</param>
        private void IconMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (e.ClickCount == 1)
            {
                if (SystemCommands.ShowSystemMenuCommand.CanExecute(null, this))
                {
                    SystemCommands.ShowSystemMenuCommand.Execute(null, this);
                }
            }
            else if (e.ClickCount == 2)
            {
                if (ApplicationCommands.Close.CanExecute(null, this))
                {
                    ApplicationCommands.Close.Execute(null, this);
                }
            }
        }

        /// <summary>
        /// Invoked when the right mouse button is pressed while the pointer is over this control.
        /// </summary>
        /// <param name="sender">Owner of the event.</param>
        /// <param name="e">Event arguments for the routed event that is raised by UIElement.</param>
        private void IconMouseRightButtonDown(object sender, MouseButtonEventArgs e)
        {
            if (SystemCommands.ShowSystemMenuCommand.CanExecute(e, this))
            {
                SystemCommands.ShowSystemMenuCommand.Execute(e, this);
            }
        }

        /// <summary>
        /// Occurs when the element is laid out, rendered, and ready for interaction. 
        /// (Inherited from FrameworkElement.)
        /// </summary>
        /// <param name="sender">Owner of the event.</param>
        /// <param name="e">Event data for the event.</param>
        private void OnMessageBoxWindowLoaded(object sender, RoutedEventArgs e) 
        {
            Loaded -= OnMessageBoxWindowLoaded;

            //set dimension according to desired size.
            SetValue(HeightProperty, measuredSize.Height);
            SetValue(WidthProperty, measuredSize.Width);

            //because the size of the window is set dynamically
            //it will not appear in the center screen.
            //hence we must set location manually.
            Left = (SystemParameters.PrimaryScreenWidth - measuredSize.Width) / 2;
            Top = (SystemParameters.PrimaryScreenHeight - measuredSize.Height) / 2;

            if (defaultFocusBtn != null) 
            {
                defaultFocusBtn.IsDefault = true;
                defaultFocusBtn.Focus();
            }
            
        }

        /// <summary>
        /// Occurs when CanExecute event is fired.
        /// </summary>
        /// <param name="sender">Owner of the event.</param>
        /// <param name="args">Event data of the event which provides data for System.Window.Input.CommandBinding.CanExecute and
        /// System.Window.Input.CommandBinding.PreviewCanExecute routed events.</param>
        private static void SystemMenuCanExecute(object sender, CanExecuteRoutedEventArgs args)
        {
            args.CanExecute = true;
        }


        /// <summary>
        /// Occurs when Execute event is fired.
        /// </summary>
        /// <param name="sender">Owner of the event.</param>
        /// <param name="args">Event data of the event which provides data for System.Window.Input.CommandBinding.Executed and
        /// System.Window.Input.CommandBinding.PreviewExecuted routed events.</param>
        private static void SystemMenuExecuted(object sender, ExecutedRoutedEventArgs args)
        {
            MessageBoxControl rw = sender as MessageBoxControl;
            if (rw != null)
            {
                // For right-clicks, display the system menu from the point of the mouse click.
                // For left-clicks, display the system menu in the top-left corner of the client area.
                Point devicePoint;
                MouseButtonEventArgs e = args.Parameter as MouseButtonEventArgs;
                if (e != null)
                {
                    // This is the right-click handler.  The presence of a MouseButtonEventArgs as args.Parameter
                    // indicates we are handling right-click.
                    devicePoint = rw.PointToScreen(e.GetPosition(rw));
                }
                else if (rw.mainBorder != null)
                {
                    // This is the left-click handler.  We can only handle it correctly if the _clientAreaBorder
                    // template part is defined, because that is where we want to position the system menu.
                    devicePoint = rw.mainBorder.PointToScreen(new Point(0, 0));
                }
                else
                {
                    // We can't handle this correctly, so exit.
                    return;
                }

                CompositionTarget compositionTarget = PresentationSource.FromVisual(rw).CompositionTarget;
                SystemCommands.ShowSystemMenu(rw, compositionTarget.TransformFromDevice.Transform(devicePoint));
                args.Handled = true;
            }
        }

        /// <summary>
        /// Window procedure WndProc
        /// </summary>
        [SecurityCritical,
         SecuritySafeCritical]
        protected virtual IntPtr WndProc(IntPtr hwnd, int msg, IntPtr wParam, IntPtr lParam, ref bool handled)
        {
            IntPtr result = IntPtr.Zero;

            NativeMethods.WindowMessages wm = (NativeMethods.WindowMessages)msg;

            if (Environment.OSVersion.Version.Major >= 6)
            {
                handled = NativeMethods.DwmDefWindowProc(hwnd, msg, wParam, lParam, out result);
            }

            if (!handled)
            {
                switch (wm)
                {
                    case NativeMethods.WindowMessages.WM_GETMINMAXINFO:

                        WmGetMinMaxInfo(hwnd, lParam);

                            handled = true;
                        break;

                    case NativeMethods.WindowMessages.WM_NCCALCSIZE:
                        handled = true;
                        result = IntPtr.Zero;
                        break;

                    case NativeMethods.WindowMessages.WM_SIZE:
                        handled = false;
                        break;

                    case NativeMethods.WindowMessages.WM_SETICON:
                        handled = true;
                        return IntPtr.Zero;

                    case NativeMethods.WindowMessages.WM_SETTEXT:
                        handled = true;
                        break;

                    case NativeMethods.WindowMessages.WM_NCLBUTTONDOWN:

                        if (WindowState == System.Windows.WindowState.Normal &&
                            ResizeMode == System.Windows.ResizeMode.CanResize)
                        {
                            SetMouseCursorAndResize(hwnd, lParam, true);
                        }
                        break;

                    case NativeMethods.WindowMessages.WM_NCMOUSEMOVE:
                        //
                        if (WindowState == System.Windows.WindowState.Normal &&
                            ResizeMode == System.Windows.ResizeMode.CanResize)
                        {
                            SetMouseCursorAndResize(hwnd, lParam, false);
                        }

                        break;

                    case NativeMethods.WindowMessages.WM_NCHITTEST:
                        if (result == System.IntPtr.Zero)
                        {
                            WndProcHitTest(hwnd, lParam, ref handled, ref result);
                            ncHitResult = (NativeMethods.HT)result;
                        }
                        break;

                    case NativeMethods.WindowMessages.WM_DWMCOMPOSITIONCHANGED:

                        //From MSDN:
                        //"If an application processes this message, it should return zero."
                        result = System.IntPtr.Zero;
                        break;
                }

            }

            return result;
        }


        private void WmGetMinMaxInfo(IntPtr hwnd, IntPtr lParam)
        {

            NativeMethods.MINMAXINFO mmi = (NativeMethods.MINMAXINFO)Marshal.PtrToStructure(lParam, typeof(NativeMethods.MINMAXINFO));

            // Adjust the maximized size and position to fit the work area of the correct monitor
            IntPtr monitor = NativeMethods.MonitorFromWindow(hwnd, (int)NativeMethods.HT.MONITOR_DEFAULTTONEAREST);

            if (monitor != System.IntPtr.Zero)
            {

                NativeMethods.MONITORINFO monitorInfo = new NativeMethods.MONITORINFO();
                NativeMethods.GetMonitorInfo(monitor, monitorInfo);
                NativeMethods.RECT rcWorkArea = monitorInfo.rcWork;
                NativeMethods.RECT rcMonitorArea = monitorInfo.rcMonitor;
                mmi.ptMaxPosition.x = Math.Abs(rcWorkArea.Left - rcMonitorArea.Left);
                mmi.ptMaxPosition.y = Math.Abs(rcWorkArea.Top - rcMonitorArea.Top);
                mmi.ptMaxSize.x = Math.Abs(rcWorkArea.Right - rcWorkArea.Left);
                mmi.ptMaxSize.y = Math.Abs(rcWorkArea.Bottom - rcWorkArea.Top);
            }

            Marshal.StructureToPtr(mmi, lParam, true);
        }

        private void SetMouseCursorAndResize(IntPtr hWnd, IntPtr lParam, bool shouldResize)
        {

            int val = -1;
            switch (ncHitResult)
            {
                case NativeMethods.HT.LEFT:
                    val = 1;
                    Mouse.SetCursor(Cursors.SizeWE);
                    break;

                case NativeMethods.HT.RIGHT:
                    val = 2;
                    Mouse.SetCursor(Cursors.SizeWE);
                    break;

                case NativeMethods.HT.TOP:
                    val = 3;
                    Mouse.SetCursor(Cursors.SizeNS);
                    break;

                case NativeMethods.HT.BOTTOM:
                    val = 6;
                    Mouse.SetCursor(Cursors.SizeNS);
                    break;

                case NativeMethods.HT.TOPLEFT:
                    val = 4;
                    Mouse.SetCursor(Cursors.SizeNWSE);
                    break;

                case NativeMethods.HT.TOPRIGHT:
                    val = 5;
                    Mouse.SetCursor(Cursors.SizeNESW);
                    break;

                case NativeMethods.HT.BOTTOMLEFT:
                    val = 7;
                    Mouse.SetCursor(Cursors.SizeNESW);
                    break;

                case NativeMethods.HT.BOTTOMRIGHT:
                    val = 8;
                    Mouse.SetCursor(Cursors.SizeNWSE);
                    break;
            }
            if (val > -1 && shouldResize)
            {
                NativeMethods.DefWindowProc(hWnd, NativeMethods.WindowMessages.WM_SYSCOMMAND, new IntPtr((int)NativeMethods.SystemCommands.SC_SIZE + val), lParam);
            }
        }
        #endregion

        #region Fields
        private const string partOuterBorder = "PART_OuterBorder", 
                             partTitleText = "PART_TitleText",
                             PART_IconName = "PART_Icon",
                             _itemsHostName = "PART_ButtonsPanel",
                             defaultButtonStyleName = "DefaultButtonStyle";
        private Panel _itemsHost = null;
        private FrameworkElement mainBorder;
        private MessageBoxResult _dialogResult = MessageBoxResult.None, defaultResult = MessageBoxResult.OK;
        private TextBlock titleText;
        private Button ok, yes, no, cancel, defaultFocusBtn = null;
        private NativeMethods.HT ncHitResult;
        internal double _resizeFrameBorderSize = 4.0D;
        private IntPtr _hwnd;
        //  private RibbonApplicationMenu ApplicationMenu { get; set; }
        //private System.Windows.Point CurrentLocation = new System.Windows.Point();
        internal Image icon;

        private Size measuredSize = new Size();

        #endregion

        #region Commands

        private static RoutedUICommand closeCommand = new RoutedUICommand("Close", "CloseCommand", typeof(MessageBoxControl));

        /// <summary>
        /// Gets Close command of the window.
        /// </summary>
        public static RoutedUICommand CloseCommand
        {
            get
            {
                return closeCommand;
            }
        }

     
        #endregion
 

    }
}

internal static class MessageBoxControlExtensions
{
    [SecurityCritical,
   SecuritySafeCritical]
    internal static void HideButtons(this MessageBoxControl window)
    {
        IntPtr hwnd = new WindowInteropHelper(window).Handle;

        int lStyle = NativeMethods.GetWindowLong(hwnd, NativeMethods.WindowStyles.GWL_STYLE);
        lStyle &= ~(NativeMethods.WindowStyles.WS_CAPTION |
                    NativeMethods.WindowStyles.WS_THICKFRAME |
                    NativeMethods.WindowStyles.WS_MINIMIZEBOX |
                    NativeMethods.WindowStyles.WS_MAXIMIZEBOX);

        NativeMethods.SetWindowLong(hwnd, NativeMethods.WindowStyles.GWL_STYLE, lStyle);

        int lExStyle = NativeMethods.GetWindowLong(hwnd, NativeMethods.WindowStyles.GWL_EXSTYLE);
        lExStyle &= ~(NativeMethods.WindowStyles.WS_EX_DLGMODALFRAME |
                      NativeMethods.WindowStyles.WS_EX_CLIENTEDGE |
                      NativeMethods.WindowStyles.WS_EX_STATICEDGE);

        NativeMethods.SetWindowLong(hwnd, NativeMethods.WindowStyles.GWL_EXSTYLE, lExStyle);

        NativeMethods.SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, NativeMethods.SWP.FRAMECHANGED |
                                                                  NativeMethods.SWP.NOMOVE |
                                                                  NativeMethods.SWP.NOSIZE |
                                                                  NativeMethods.SWP.NOZORDER);
    }

    internal static void EnableClassicStyle(this MessageBoxControl window)
    {
        IntPtr hwnd = new WindowInteropHelper(window).Handle;

        if (hwnd != IntPtr.Zero)
        {
            EnableDefaulWindow(window);
        }
        else
        {
            window.Loaded += EnableDefaultStyleOnLoaded;
        }

    }

    internal static void EnableDefaultStyleOnLoaded(object sender, EventArgs e)
    {
        MessageBoxControl window = sender as MessageBoxControl;
        window.Loaded -= EnableDefaultStyleOnLoaded;
        EnableDefaulWindow(window);

    }

    [SecurityCritical,
    SecuritySafeCritical]
    internal static void EnableDefaulWindow(MessageBoxControl window)
    {
        IntPtr hwnd = new WindowInteropHelper(window).Handle;

        HwndSource src = HwndSource.FromHwnd(hwnd);
        //// settings the following value is necassary to have a transparent glass background instead of black:
        src.CompositionTarget.BackgroundColor = Color.FromArgb(0, 0, 0, 0);

        int lStyle = NativeMethods.GetWindowLong(hwnd, NativeMethods.WindowStyles.GWL_STYLE);
        lStyle |= NativeMethods.WindowStyles.WS_CAPTION | NativeMethods.WindowStyles.WS_THICKFRAME | NativeMethods.WindowStyles.WS_MINIMIZEBOX | NativeMethods.WindowStyles.WS_MAXIMIZEBOX;

        NativeMethods.SetWindowLong(hwnd, NativeMethods.WindowStyles.GWL_STYLE, lStyle);

        int lExStyle = NativeMethods.GetWindowLong(hwnd, NativeMethods.WindowStyles.GWL_EXSTYLE);

        lExStyle |= NativeMethods.WindowStyles.WS_EX_DLGMODALFRAME | NativeMethods.WindowStyles.WS_EX_STATICEDGE;
        NativeMethods.SetWindowLong(hwnd, NativeMethods.WindowStyles.GWL_EXSTYLE, lExStyle);

        NativeMethods.SetWindowPos(hwnd, IntPtr.Zero, 0, 0, 0, 0, NativeMethods.SWP.FRAMECHANGED | NativeMethods.SWP.NOMOVE | NativeMethods.SWP.NOSIZE | NativeMethods.SWP.NOZORDER);

        NativeMethods.MARGINS margins = new NativeMethods.MARGINS();
        margins.cxLeftWidth = (int)window._resizeFrameBorderSize;
        margins.cxRightWidth = (int)window._resizeFrameBorderSize;
        margins.cyTopHeight = (int)System.Windows.SystemParameters.CaptionHeight + (int)window._resizeFrameBorderSize;
        margins.cyBottomHeight = (int)window._resizeFrameBorderSize;
        NativeMethods.DwmExtendFrameIntoClientArea(hwnd, ref margins);

    }
}